import PanelBase from "../Component/PanelBase";
import DebugExt from "../base/DebugExt";
import CanvasExt from "./CanvasExt";

/** panel base info */
interface IPanelBaseInfo {
    panel: PanelBase,
    parent: cc.Node,
    isloading: boolean,
    prefab: cc.Prefab
}

/** show panel base param */
export interface IPanelBaseParam {
    /** panel名 */
    key: string,
    /**
     * [可忽略] 父节点；
     * *空值:
     * 1、优先 挂载到 key+"Parent"名称节点；
     * 2、其次 挂载到当前场景最高层级；
     */
    parent?: cc.Node,
    /**
     * [可忽略] prefab预制体resource下路径
     * 默认 "resources/prefabs/"+key
     */
    url?: string,
    /** 额外附带自定义参数 */
    exData?: any
}

/**
 * 通用panel预制体管理单例
 */
export default class PanelManager {

    private static _ins: PanelManager = null;
    private constructor() {
        globalThis.PanelManager = PanelManager;
    }
    public static getIns(): PanelManager {
        if (!this._ins)
            this._ins = new PanelManager();
        return this._ins;
    }

    public static destory() {
        if (this._ins) {
            delete this._ins;
            this._ins = null;
        }
    }

    /**
     * 预加载指定名称的panel预制体
     * @param p 
     * @returns 
     */
    public async preload(p: IPanelBaseParam) {
        if (!p || !p.key) {
            DebugExt.warn("PanelManager.preload参数异常：", p);
            return;
        }
        const info = this._panelList.get(p.key);
        if (info && info.isloading) {
            DebugExt.tips("PanelManager ", p.key, " isPreloading");
        }
        else if (info && !!info.prefab && info.prefab.isValid) {
            DebugExt.tips("PanelManager ", p.key, " isPreloaded");
        }
        else {
            let nInfo: IPanelBaseInfo = {
                panel: null,
                parent: null,
                isloading: false,
                prefab: null
            };
            this._panelList.set(p.key, nInfo);
            const prefab = await this.loadPrefab(this.getUrlPath(p));
            nInfo.isloading = false;
            if (prefab) {
                nInfo.prefab = prefab;
                DebugExt.tips("PanelManager ", p.key, " isPreloaded");
            }
        }
    }

    /**
     * 显示指定名称的panel
     */
    public async show(p: IPanelBaseParam) {
        if (!p || !p.key) {
            DebugExt.warn("PanelManager.show参数异常：", p);
            return;
        }
        const info = this._panelList.get(p.key);
        if (info && !!info.panel && info.panel.isValid) {
            info.panel.show(p.exData);
        }
        else if (info && info.isloading) {
            DebugExt.tips("PanelManager ", p.key, " isShowing");
        }
        else if (info && !!info.prefab && info.prefab.isValid) {
            const parent = this.getParent(p);
            info.parent = parent;
            const node = cc.instantiate(info.prefab);
            node.setPosition(cc.Vec2.ZERO);
            parent.addChild(node);
            info.panel = node.getComponent(PanelBase);
            info.panel.show(p.exData);
        }
        else {
            const parent = this.getParent(p);
            let nInfo: IPanelBaseInfo = {
                panel: null,
                parent,
                isloading: true,
                prefab: null
            };
            this._panelList.set(p.key, nInfo);
            const prefab = await this.loadPrefab(this.getUrlPath(p));
            nInfo.isloading = false;
            if (prefab) {
                nInfo.prefab = prefab;
                const node = cc.instantiate(prefab);
                node.setPosition(cc.Vec2.ZERO);
                parent.addChild(node);
                nInfo.panel = node.getComponent(PanelBase);
                nInfo.panel.show(p.exData);
            }
        }
    }

    private getUrlPath(p: IPanelBaseParam): string {
        let urlpath = "";
        if (p.url)
            urlpath = p.url;
        else {
            urlpath = "prefabs/" + p.key;
        }
        return urlpath;
    }

    private getParent(p: IPanelBaseParam): cc.Node {
        if (p.parent && p.parent.isValid)
            return p.parent;

        const baseInfo = this._panelList.get(p.key)
        if (baseInfo && baseInfo.parent && baseInfo.parent.isValid)
            return baseInfo.parent;

        let parent = null;
        parent = CanvasExt.getNode(p.key + "Parent", null, true);
        if (!parent)
            parent = CanvasExt.canvasNode;
        return parent;
    }

    private _panelList: Map<string, IPanelBaseInfo> = new Map();

    /** load prefab */
    private async loadPrefab(url: string): Promise<cc.Prefab> {
        return new Promise<any>((resolve, reject) => {
            cc.loader.loadRes(url, cc.Prefab, (error: Error, resource: cc.Prefab) => {
                if (error) {
                    DebugExt.warn(error);
                    resolve(null);
                } else {
                    resolve(resource);
                }
            })
        });
    }
}
